using System;
using System.Collections;
using System.Collections.Generic;
using Oracle.ManagedDataAccess.Client;
using OracleInternal.Common;
using OracleInternal.ConnectionPool;

namespace OracleInternal.BinXml
{
	internal class ObxmlTokenManager : IDisposable
	{
		private ObxmlMetaDataRepository m_DefaultMetaDataRepository = new ObxmlMetaDataRepository();

		private bool m_bOwnsMetaDataRepository;

		private Hashtable m_TokenMapHash = new Hashtable();

		private static int m_MaxTokenPoolEntries;

		private static int m_MaxTokenPoolSize;

		private OraclePoolManager m_parent;

		private object m_tokenMapLock = new object();

		internal static bool ClientDecodeEnabled => ConfigBaseClass.m_XMLTypeClientSideDecoding;

		internal static int MaxTokenPoolEntries
		{
			get
			{
				if (m_MaxTokenPoolEntries != 0)
				{
					return m_MaxTokenPoolEntries;
				}
				return m_MaxTokenPoolEntries = ObxmlDecodeContext.m_XMLTypeMaxCacheEntries;
			}
		}

		internal int Count => m_TokenMapHash.Count;

		internal ObxmlTokenManager(OraclePoolManager parent)
		{
			if (parent == null)
			{
				throw new OracleException(ResourceStringConstants.XML_TYPE_BINARY_INTERNAL_ERROR, string.Empty, string.Empty, ObxmlDecodeResponse.GetErrorMessage(ObxmlErrorTypes.InvalidArguments));
			}
			m_parent = parent;
		}

		static ObxmlTokenManager()
		{
		}

		internal static ObxmlTokenManager GetOracleBinXmlTokenManager(ObxmlDecodeContext decodeContext)
		{
			if (decodeContext == null)
			{
				throw new OracleException(ResourceStringConstants.XML_TYPE_BINARY_INTERNAL_ERROR, string.Empty, string.Empty, ObxmlDecodeResponse.GetErrorMessage(ObxmlErrorTypes.InvalidArguments));
			}
			return GetOracleBinXmlTokenManager(decodeContext.DbConnection);
		}

		internal static ObxmlTokenManager GetOracleBinXmlTokenManager(OracleConnection dbConnection)
		{
			if (dbConnection == null)
			{
				throw new OracleException(ResourceStringConstants.XML_TYPE_BINARY_INTERNAL_ERROR, string.Empty, string.Empty, ObxmlDecodeResponse.GetErrorMessage(ObxmlErrorTypes.InvalidArguments));
			}
			return dbConnection.m_oracleConnectionImpl.m_pm.m_xmlTokenManager;
		}

		internal ObxmlMetaDataRepository GetDefaultMetaDataRepository(bool bDisposeMetaDataRepository, ObxmlDecodeContext decodeContext = null)
		{
			m_bOwnsMetaDataRepository = bDisposeMetaDataRepository;
			return m_DefaultMetaDataRepository;
		}

		internal ObxmlTokenMap Open(ObxmlTokenManagerContext tmContext)
		{
			ObxmlTokenMap obxmlTokenMap = null;
			if (tmContext == null || !tmContext.IsValid)
			{
				throw new OracleException(ResourceStringConstants.XML_TYPE_BINARY_INTERNAL_ERROR, string.Empty, string.Empty, ObxmlDecodeResponse.GetErrorMessage(ObxmlErrorTypes.TokenCacheCorrupt));
			}
			lock (m_tokenMapLock)
			{
				if ((obxmlTokenMap = GetMap(tmContext.PartitionId)) != null)
				{
					return obxmlTokenMap;
				}
				obxmlTokenMap = new ObxmlTokenMap(tmContext, TokenTypes.None);
				SetMap(ref obxmlTokenMap, obxmlTokenMap.PartitionId);
				return obxmlTokenMap;
			}
		}

		internal ObxmlTokenMap Open(string partitionId)
		{
			return null;
		}

		internal void Close(ObxmlTokenMap tokenMap)
		{
		}

		internal void Close(string partitionId)
		{
		}

		internal void Clear(ObxmlTokenMap tokenMap)
		{
		}

		internal void Clear(string partitionId)
		{
		}

		public void Dispose()
		{
			Dispose(disposing: true);
			GC.SuppressFinalize(this);
		}

		protected virtual void Dispose(bool disposing)
		{
			if (disposing)
			{
				if (m_TokenMapHash != null)
				{
					m_TokenMapHash.Clear();
					m_TokenMapHash = null;
				}
				if (m_bOwnsMetaDataRepository && m_DefaultMetaDataRepository != null)
				{
					m_DefaultMetaDataRepository.Dispose();
					m_DefaultMetaDataRepository = null;
				}
			}
		}

		internal void PurgeTokenMaps(List<string> lruPartitionsList, int thresHold)
		{
			lock (m_tokenMapLock)
			{
				if (lruPartitionsList != null || thresHold != -1)
				{
					return;
				}
				foreach (ObxmlTokenMap item in m_TokenMapHash)
				{
					item.Clear();
				}
			}
		}

		private void SetMap(ref ObxmlTokenMap tokenMap, string partitionId)
		{
			if (!m_TokenMapHash.Contains(partitionId))
			{
				m_TokenMapHash.Add(partitionId, tokenMap);
			}
			else
			{
				tokenMap = (ObxmlTokenMap)m_TokenMapHash[partitionId];
			}
		}

		private ObxmlTokenMap GetMap(string partitionId)
		{
			try
			{
				return (ObxmlTokenMap)m_TokenMapHash[partitionId];
			}
			catch (Exception)
			{
			}
			return null;
		}
	}
}
